<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="keywords" content="Hexo Theme Redefine">
    
    <meta name="author" content="xiaoeryu">
    <!-- preconnect -->
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

    
    <!--- Seo Part-->
    
    <link rel="canonical" href="https://xiaoeeyu.github.io/2024/04/10/linkhook-init-array自吐/"/>
    <meta name="robots" content="index,follow">
    <meta name="googlebot" content="index,follow">
    <meta name="revisit-after" content="1 days">
    
    
    
        
        <meta name="description" content="本章的主要内容为  通过源码分析init_array原理so加载执行流程 hook_linker init_array 自吐">
<meta property="og:type" content="article">
<meta property="og:title" content="linkHook_init_array自吐">
<meta property="og:url" content="https://xiaoeeyu.github.io/2024/04/10/linkHook-init-array%E8%87%AA%E5%90%90/index.html">
<meta property="og:site_name" content="xiaoeryu">
<meta property="og:description" content="本章的主要内容为  通过源码分析init_array原理so加载执行流程 hook_linker init_array 自吐">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://xiaoeeyu.github.io/2024/04/10/linkHook-init-array%E8%87%AA%E5%90%90/image-20240405211947048.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2024/04/10/linkHook-init-array%E8%87%AA%E5%90%90/image-20240405212720542.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2024/04/10/linkHook-init-array%E8%87%AA%E5%90%90/image-20240326211109629.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2024/04/10/linkHook-init-array%E8%87%AA%E5%90%90/image-20240326211308718.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2024/04/10/linkHook-init-array%E8%87%AA%E5%90%90/image-20240326211337950.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2024/04/10/linkHook-init-array%E8%87%AA%E5%90%90/image-20240326213902401.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2024/04/10/linkHook-init-array%E8%87%AA%E5%90%90/image-20240326214454916.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2024/04/10/linkHook-init-array%E8%87%AA%E5%90%90/image-20240404213119392.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2024/04/10/linkHook-init-array%E8%87%AA%E5%90%90/image-20240404213731538.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2024/04/10/linkHook-init-array%E8%87%AA%E5%90%90/image-20240405221059543.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2024/04/10/linkHook-init-array%E8%87%AA%E5%90%90/image-20240410003035124.png">
<meta property="og:image" content="https://xiaoeeyu.github.io/2024/04/10/linkHook-init-array%E8%87%AA%E5%90%90/image-20240410091216247.png">
<meta property="article:published_time" content="2024-04-10T01:16:22.000Z">
<meta property="article:modified_time" content="2024-08-06T14:19:29.329Z">
<meta property="article:author" content="xiaoeryu">
<meta property="article:tag" content="Frida Hook">
<meta property="article:tag" content="框架层Hook">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://xiaoeeyu.github.io/2024/04/10/linkHook-init-array%E8%87%AA%E5%90%90/image-20240405211947048.png">
    
    
    <!--- Icon Part-->
    <link rel="icon" type="image/png" href="/images/rabete.jpg" sizes="192x192">
    <link rel="apple-touch-icon" sizes="180x180" href="/images/rabete.jpg">
    <meta name="theme-color" content="#A31F34">
    <link rel="shortcut icon" href="/images/rabete.jpg">
    <!--- Page Info-->
    
    <title>
        
            linkHook_init_array自吐 | xiaoeryu
        
    </title>

    
<link rel="stylesheet" href="/fonts/Chillax/chillax.css">


    <!--- Inject Part-->
    

    
<link rel="stylesheet" href="/css/style.css">


    
        
<link rel="stylesheet" href="/css/build/tailwind.css">

    

    
<link rel="stylesheet" href="/fonts/GeistMono/geist-mono.css">

    
<link rel="stylesheet" href="/fonts/Geist/geist.css">

    <!--- Font Part-->
    
    
    
    
    
    

    <script id="hexo-configurations">
    window.config = {"hostname":"xiaoeeyu.github.io","root":"/","language":"zh-CN","path":"search.xml"};
    window.theme = {"articles":{"style":{"font_size":"16px","line_height":1.5,"image_border_radius":"14px","image_alignment":"center","image_caption":false,"link_icon":true,"delete_mask":false,"title_alignment":"left","headings_top_spacing":{"h1":"3.2rem","h2":"2.4rem","h3":"1.9rem","h4":"1.6rem","h5":"1.4rem","h6":"1.3rem"}},"word_count":{"enable":true,"count":true,"min2read":true},"author_label":{"enable":true,"auto":false,"list":[]},"code_block":{"copy":true,"style":"mac","highlight_theme":{"light":"github","dark":"vs2015"},"font":{"enable":false,"family":null,"url":null}},"toc":{"enable":true,"max_depth":4,"number":false,"expand":true,"init_open":true},"copyright":{"enable":true,"default":"cc_by_nc_sa"},"lazyload":true,"pangu_js":false,"recommendation":{"enable":false,"title":"推荐阅读","limit":3,"mobile_limit":2,"placeholder":"/images/ball-0101.jpg","skip_dirs":[]}},"colors":{"primary":"#A31F34","secondary":null,"default_mode":"light"},"global":{"fonts":{"chinese":{"enable":false,"family":null,"url":null},"english":{"enable":false,"family":null,"url":null},"title":{"enable":false,"family":null,"url":null}},"content_max_width":"1000px","sidebar_width":"210px","hover":{"shadow":true,"scale":false},"scroll_progress":{"bar":false,"percentage":true},"website_counter":{"url":"https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js","enable":true,"site_pv":true,"site_uv":true,"post_pv":true},"single_page":true,"preloader":{"enable":false,"custom_message":null},"open_graph":true,"google_analytics":{"enable":false,"id":null}},"home_banner":{"enable":true,"style":"fixed","image":{"light":"/images/wallhaven-jxl31y.png","dark":"/images/wallhaven-o5762l.png"},"title":"XIAOERYU","subtitle":{"text":["明心见性，拨云见日","Don't wait, to create"],"hitokoto":{"enable":false,"show_author":false,"api":"https://v1.hitokoto.cn"},"typing_speed":100,"backing_speed":80,"starting_delay":500,"backing_delay":1500,"loop":true,"smart_backspace":true},"text_color":{"light":"#fff","dark":"#d1d1b6"},"text_style":{"title_size":"2.8rem","subtitle_size":"1.5rem","line_height":1.2},"custom_font":{"enable":false,"family":null,"url":null},"social_links":{"enable":true,"style":"default","links":{"github":"https://github.com/xiaoeeyu","instagram":null,"zhihu":null,"twitter":null,"email":"xiaoeryu@163.com"},"qrs":{"weixin":null}}},"plugins":{"feed":{"enable":false},"aplayer":{"enable":false,"type":"fixed","audios":[{"name":null,"artist":null,"url":null,"cover":null,"lrc":null}]},"mermaid":{"enable":false,"version":"9.3.0"}},"version":"2.8.2","navbar":{"auto_hide":false,"color":{"left":"#f78736","right":"#367df7","transparency":35},"width":{"home":"1200px","pages":"1000px"},"links":{"Home":{"path":"/","icon":"fa-regular fa-house"},"Archives":{"path":"/archives","icon":"fa-regular fa-archive"}},"search":{"enable":true,"preload":true}},"page_templates":{"friends_column":2,"tags_style":"blur"},"home":{"sidebar":{"enable":true,"position":"left","first_item":"menu","announcement":null,"show_on_mobile":true,"links":null},"article_date_format":"auto","excerpt_length":200,"categories":{"enable":true,"limit":3},"tags":{"enable":true,"limit":3}},"footerStart":"2022/8/17 11:45:14"};
    window.lang_ago = {"second":"%s 秒前","minute":"%s 分钟前","hour":"%s 小时前","day":"%s 天前","week":"%s 周前","month":"%s 个月前","year":"%s 年前"};
    window.data = {"masonry":false};
  </script>
    
    <!--- Fontawesome Part-->
    
<link rel="stylesheet" href="/fontawesome/fontawesome.min.css">

    
<link rel="stylesheet" href="/fontawesome/brands.min.css">

    
<link rel="stylesheet" href="/fontawesome/solid.min.css">

    
<link rel="stylesheet" href="/fontawesome/regular.min.css">

    
    
    
    
<meta name="generator" content="Hexo 6.3.0">
<style>.github-emoji { position: relative; display: inline-block; width: 1.2em; min-height: 1.2em; overflow: hidden; vertical-align: top; color: transparent; }  .github-emoji > span { position: relative; z-index: 10; }  .github-emoji img, .github-emoji .fancybox { margin: 0 !important; padding: 0 !important; border: none !important; outline: none !important; text-decoration: none !important; user-select: none !important; cursor: auto !important; }  .github-emoji img { height: 1.2em !important; width: 1.2em !important; position: absolute !important; left: 50% !important; top: 50% !important; transform: translate(-50%, -50%) !important; user-select: none !important; cursor: auto !important; } .github-emoji-fallback { color: inherit; } .github-emoji-fallback img { opacity: 0 !important; }</style>
</head>



<body>
	<div class="progress-bar-container">
	

	
	<span class="pjax-progress-bar"></span>
	<!--        <span class="swup-progress-icon">-->
	<!--            <i class="fa-solid fa-circle-notch fa-spin"></i>-->
	<!--        </span>-->
	
</div>

<main class="page-container" id="swup">

	

	<div class="main-content-container flex flex-col justify-between min-h-dvh">
		<div class="main-content-header">
			<header class="navbar-container px-6 md:px-12">
    <div class="navbar-content transition-navbar ">
        <div class="left">
            
                <a class="logo-image h-8 w-8 sm:w-10 sm:h-10 mr-3" href="/">
                    <img src="/images/rabete.jpg" class="w-full h-full rounded-sm">
                </a>
            
            <a class="logo-title" href="/">
                
                xiaoeryu
                
            </a>
        </div>

        <div class="right">
            <!-- PC -->
            <div class="desktop">
                <ul class="navbar-list">
                    
                        
                            

                            <li class="navbar-item">
                                <!-- Menu -->
                                <a class=""
                                   href="/"
                                        >
                                    <i class="fa-regular fa-house fa-fw"></i>
                                    首页
                                    
                                </a>

                                <!-- Submenu -->
                                
                            </li>
                    
                        
                            

                            <li class="navbar-item">
                                <!-- Menu -->
                                <a class=""
                                   href="/archives"
                                        >
                                    <i class="fa-regular fa-archive fa-fw"></i>
                                    归档
                                    
                                </a>

                                <!-- Submenu -->
                                
                            </li>
                    
                    
                        <li class="navbar-item search search-popup-trigger">
                            <i class="fa-solid fa-magnifying-glass"></i>
                        </li>
                    
                </ul>
            </div>
            <!-- Mobile -->
            <div class="mobile">
                
                    <div class="icon-item search search-popup-trigger"><i class="fa-solid fa-magnifying-glass"></i>
                    </div>
                
                <div class="icon-item navbar-bar">
                    <div class="navbar-bar-middle"></div>
                </div>
            </div>
        </div>
    </div>

    <!-- Mobile sheet -->
    <div class="navbar-drawer h-dvh w-full absolute top-0 left-0 bg-background-color flex flex-col justify-between">
        <ul class="drawer-navbar-list flex flex-col px-4 justify-center items-start">
            
                
                    

                    <li class="drawer-navbar-item text-base my-1.5 flex flex-col w-full">
                        
                        <a class="py-1.5 px-2 flex flex-row items-center justify-between gap-1 hover:!text-primary active:!text-primary text-2xl font-semibold group border-b border-border-color hover:border-primary w-full "
                           href="/"
                        >
                            <span>
                                首页
                            </span>
                            
                                <i class="fa-regular fa-house fa-sm fa-fw"></i>
                            
                        </a>
                        

                        
                    </li>
            
                
                    

                    <li class="drawer-navbar-item text-base my-1.5 flex flex-col w-full">
                        
                        <a class="py-1.5 px-2 flex flex-row items-center justify-between gap-1 hover:!text-primary active:!text-primary text-2xl font-semibold group border-b border-border-color hover:border-primary w-full "
                           href="/archives"
                        >
                            <span>
                                归档
                            </span>
                            
                                <i class="fa-regular fa-archive fa-sm fa-fw"></i>
                            
                        </a>
                        

                        
                    </li>
            

            
            
        </ul>

        <div class="statistics flex justify-around my-2.5">
    <a class="item tag-count-item flex flex-col justify-center items-center w-20" href="/tags">
        <div class="number text-2xl sm:text-xl text-second-text-color font-semibold">92</div>
        <div class="label text-third-text-color text-sm">标签</div>
    </a>
    <a class="item tag-count-item flex flex-col justify-center items-center w-20" href="/categories">
        <div class="number text-2xl sm:text-xl text-second-text-color font-semibold">14</div>
        <div class="label text-third-text-color text-sm">分类</div>
    </a>
    <a class="item tag-count-item flex flex-col justify-center items-center w-20" href="/archives">
        <div class="number text-2xl sm:text-xl text-second-text-color font-semibold">112</div>
        <div class="label text-third-text-color text-sm">文章</div>
    </a>
</div>
    </div>

    <div class="window-mask"></div>

</header>


		</div>

		<div class="main-content-body transition-fade-up">
			

			<div class="main-content">
				<div class="post-page-container flex relative justify-between box-border w-full h-full">
	<div class="article-content-container">

		<div class="article-title relative w-full">
			
			<div class="w-full flex items-center pt-6 justify-start">
				<h1 class="article-title-regular text-second-text-color tracking-tight text-4xl md:text-6xl font-semibold px-2 sm:px-6 md:px-8 py-3">linkHook_init_array自吐</h1>
			</div>
			
		</div>

		
		<div class="article-header flex flex-row gap-2 items-center px-2 sm:px-6 md:px-8">
			<div class="avatar w-[46px] h-[46px] flex-shrink-0 rounded-medium border border-border-color p-[1px]">
				<img src="/images/rabete.jpg">
			</div>
			<div class="info flex flex-col justify-between">
				<div class="author flex items-center">
					<span class="name text-default-text-color text-lg font-semibold">xiaoeryu</span>
					
					<span class="author-label ml-1.5 text-xs px-2 py-0.5 rounded-small text-third-text-color border border-shadow-color-1">Lv5</span>
					
				</div>
				<div class="meta-info">
					<div class="article-meta-info">
    <span class="article-date article-meta-item">
        <i class="fa-regular fa-pen-fancy"></i>&nbsp;
        <span class="desktop">2024-04-10 09:16:22</span>
        <span class="mobile">2024-04-10 09:16:22</span>
        <span class="hover-info">创建</span>
    </span>
    
        <span class="article-date article-meta-item">
            <i class="fa-regular fa-wrench"></i>&nbsp;
            <span class="desktop">2024-08-06 22:19:29</span>
            <span class="mobile">2024-08-06 22:19:29</span>
            <span class="hover-info">更新</span>
        </span>
    

    
        <span class="article-categories article-meta-item">
            <i class="fa-regular fa-folders"></i>&nbsp;
            <ul>
                
                
                    
                        
                        <li>
                            <a href="/categories/Android%E9%80%86%E5%90%91/">Android逆向</a>&nbsp;
                        </li>
                    
                    
                
            </ul>
        </span>
    
    
        <span class="article-tags article-meta-item">
            <i class="fa-regular fa-tags"></i>&nbsp;
            <ul>
                
                    <li>
                        <a href="/tags/Frida-Hook/">Frida Hook</a>&nbsp;
                    </li>
                
                    <li>
                        | <a href="/tags/%E6%A1%86%E6%9E%B6%E5%B1%82Hook/">框架层Hook</a>&nbsp;
                    </li>
                
            </ul>
        </span>
    

    
    
    
    
        <span class="article-pv article-meta-item">
            <i class="fa-regular fa-eye"></i>&nbsp;<span id="busuanzi_value_page_pv"></span>
        </span>
    
</div>

				</div>
			</div>
		</div>
		

		


		<div class="article-content markdown-body px-2 sm:px-6 md:px-8 pb-8">
			<p>本章的主要内容为</p>
<ul>
<li>通过源码分析init_array原理so加载执行流程</li>
<li>hook_linker init_array 自吐</li>
</ul>
<span id="more"></span>

<p>在对<strong>linker</strong>进行hook之前先分析一下so文件的加载流程</p>
<p>在so被加载之后，如果so文件中存在<code>.init</code>和<code>.init_array</code>段的话它们会先被动态链接器调用进行一些初始化的操作。所以这两个函数无论有没有被调用它都会优先执行</p>
<img lazyload="" src="/images/loading.svg" data-src="/2024/04/10/linkHook-init-array%E8%87%AA%E5%90%90/image-20240405211947048.png" class="" title="image-20240405211947048">

<img lazyload="" src="/images/loading.svg" data-src="/2024/04/10/linkHook-init-array%E8%87%AA%E5%90%90/image-20240405212720542.png" class="" title="image-20240405212720542">

<ul>
<li>例如这里我们并没有主动调用这个<code>_init()</code>，但是它还是会在so加载的时候主动执行</li>
</ul>
<p>去源码中搜索一下加载so的<code>dlopen</code>函数调用过程</p>
<h3 id="源码分析"><a href="#源码分析" class="headerlink" title="源码分析"></a>源码分析</h3><p>测试用的设备是Android 10.0所以这里以<a class="link" target="_blank" rel="noopener" href="http://aospxref.com/android-10.0.0_r47/">Android 10.0的源码<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a>为例，到目前最新的Android14为止对so的加载都是通过<code>dlopen()</code>进行的</p>
<img lazyload="" src="/images/loading.svg" data-src="/2024/04/10/linkHook-init-array%E8%87%AA%E5%90%90/image-20240326211109629.png" class="" title="image-20240326211109629">

<img lazyload="" src="/images/loading.svg" data-src="/2024/04/10/linkHook-init-array%E8%87%AA%E5%90%90/image-20240326211308718.png" class="" title="image-20240326211308718">

<img lazyload="" src="/images/loading.svg" data-src="/2024/04/10/linkHook-init-array%E8%87%AA%E5%90%90/image-20240326211337950.png" class="" title="image-20240326211337950">

<pre><code class="c++">void* do_dlopen(const char* name, int flags,
                const android_dlextinfo* extinfo,
                const void* caller_addr) {
    // 创建一个带有"dlopen: "前缀的跟踪对象，用于记录加载库的跟踪信息
  std::string trace_prefix = std::string("dlopen: ") + (name == nullptr ? "(nullptr)" : name);
  ScopedTrace trace(trace_prefix.c_str());
    // 创建一个带有"dlopen: - loading and linking"前缀的跟踪对象，用于记录加载和链接库的跟踪信息
  ScopedTrace loading_trace((trace_prefix + " - loading and linking").c_str());
    // 查找调用者的soinfo结构体
  soinfo* const caller = find_containing_library(caller_addr);
    // 获取调用者的命名空间
  android_namespace_t* ns = get_caller_namespace(caller);
    // 记录dlopen调用的详细信息
  LD_LOG(kLogDlopen,
         "dlopen(name=\"%s\", flags=0x%x, extinfo=%s, caller=\"%s\", caller_ns=%s@%p, targetSdkVersion=%i) ...",
         name,
         flags,
         android_dlextinfo_to_string(extinfo).c_str(),
         caller == nullptr ? "(null)" : caller-&gt;get_realpath(),
         ns == nullptr ? "(null)" : ns-&gt;get_name(),
         ns,
         get_application_target_sdk_version());
    // 创建自动清理对象，用于在作用域结束时调用purge_unused_memory函数
  auto purge_guard = android::base::make_scope_guard([&amp;]() { purge_unused_memory(); });
    // 创建自动清理对象，用于在作用域结束时记录dlopen失败信息
  auto failure_guard = android::base::make_scope_guard(
      [&amp;]() { LD_LOG(kLogDlopen, "... dlopen failed: %s", linker_get_error_buffer()); });
    // 检查flags是否包含无效标志，如果包含则返回nullptr
  if ((flags &amp; ~(RTLD_NOW|RTLD_LAZY|RTLD_LOCAL|RTLD_GLOBAL|RTLD_NODELETE|RTLD_NOLOAD)) != 0) {
    DL_ERR("invalid flags to dlopen: %x", flags);
    return nullptr;
  }
    // 检查extinfo是否包含无效标志，如果包含则返回nullptr
  if (extinfo != nullptr) {
    if ((extinfo-&gt;flags &amp; ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
      DL_ERR("invalid extended flags to android_dlopen_ext: 0x%" PRIx64, extinfo-&gt;flags);
      return nullptr;
    }

    if ((extinfo-&gt;flags &amp; ANDROID_DLEXT_USE_LIBRARY_FD) == 0 &amp;&amp;
        (extinfo-&gt;flags &amp; ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
      DL_ERR("invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without "
          "ANDROID_DLEXT_USE_LIBRARY_FD): 0x%" PRIx64, extinfo-&gt;flags);
      return nullptr;
    }

    if ((extinfo-&gt;flags &amp; ANDROID_DLEXT_USE_NAMESPACE) != 0) {
      if (extinfo-&gt;library_namespace == nullptr) {
        DL_ERR("ANDROID_DLEXT_USE_NAMESPACE is set but extinfo-&gt;library_namespace is null");
        return nullptr;
      }
      ns = extinfo-&gt;library_namespace;
    }
  }

  // Workaround for dlopen(/system/lib/&lt;soname&gt;) when .so is in /apex. http://b/121248172
  // The workaround works only when targetSdkVersion &lt; Q.
  std::string name_to_apex;
  if (translateSystemPathToApexPath(name, &amp;name_to_apex)) {
    const char* new_name = name_to_apex.c_str();
    LD_LOG(kLogDlopen, "dlopen considering translation from %s to APEX path %s",
           name,
           new_name);
    // Some APEXs could be optionally disabled. Only translate the path
    // when the old file is absent and the new file exists.
    // TODO(b/124218500): Re-enable it once app compat issue is resolved
    /*
    if (file_exists(name)) {
      LD_LOG(kLogDlopen, "dlopen %s exists, not translating", name);
    } else
    */
    if (!file_exists(new_name)) {
      LD_LOG(kLogDlopen, "dlopen %s does not exist, not translating",
             new_name);
    } else {
      LD_LOG(kLogDlopen, "dlopen translation accepted: using %s", new_name);
      name = new_name;
    }
  }
  // End Workaround for dlopen(/system/lib/&lt;soname&gt;) when .so is in /apex.

  std::string asan_name_holder;

  const char* translated_name = name;
  if (g_is_asan &amp;&amp; translated_name != nullptr &amp;&amp; translated_name[0] == '/') {
    char original_path[PATH_MAX];
    if (realpath(name, original_path) != nullptr) {
      asan_name_holder = std::string(kAsanLibDirPrefix) + original_path;
      if (file_exists(asan_name_holder.c_str())) {
        soinfo* si = nullptr;
        if (find_loaded_library_by_realpath(ns, original_path, true, &amp;si)) {
          PRINT("linker_asan dlopen NOT translating \"%s\" -&gt; \"%s\": library already loaded", name,
                asan_name_holder.c_str());
        } else {
          PRINT("linker_asan dlopen translating \"%s\" -&gt; \"%s\"", name, translated_name);
          translated_name = asan_name_holder.c_str();
        }
      }
    }
  }
    // 创建受保护的数据对象，用于在加载库期间保护数据
  ProtectedDataGuard guard;
    // 在命名空间中查找库并加载
  soinfo* si = find_library(ns, translated_name, flags, extinfo, caller);
  loading_trace.End();
    // 如果加载成功，则调用构造函数，并记录加载信息，然后返回句柄
  if (si != nullptr) {
    void* handle = si-&gt;to_handle();
    LD_LOG(kLogDlopen,
           "... dlopen calling constructors: realpath=\"%s\", soname=\"%s\", handle=%p",
           si-&gt;get_realpath(), si-&gt;get_soname(), handle);
      // 调用库的构造函数
    si-&gt;call_constructors();	// &lt;&lt;&lt;&lt;&lt; 跟进看看之后的调用流程
      // 禁用dlopen失败的清理回调
    failure_guard.Disable();
      // 记录加载成功的信息，并返回句柄
    LD_LOG(kLogDlopen,
           "... dlopen successful: realpath=\"%s\", soname=\"%s\", handle=%p",
           si-&gt;get_realpath(), si-&gt;get_soname(), handle);
    return handle;
  }
    // 如果加载失败，则返回nullptr
  return nullptr;
}
</code></pre>
<ul>
<li>这段代码前面做了一堆非空值的判断</li>
<li>然后调用<code>si-&gt;call_constructors()</code>来完成so函数的加载</li>
</ul>
<p>进入<code>si-&gt;call_constructors()</code>后<strong>DT_INIT</strong>以及<strong>DT_INIT_ARRAY</strong>会依次执行</p>
<img lazyload="" src="/images/loading.svg" data-src="/2024/04/10/linkHook-init-array%E8%87%AA%E5%90%90/image-20240326213902401.png" class="" title="image-20240326213902401">

<img lazyload="" src="/images/loading.svg" data-src="/2024/04/10/linkHook-init-array%E8%87%AA%E5%90%90/image-20240326214454916.png" class="" title="image-20240326214454916">

<ul>
<li><p>不论<strong>DT_INIT</strong>还是<strong>DT_INIT_ARRAY</strong>都是通过<code>call_function()</code>调用执行</p>
</li>
<li><p>其中的<code>call_array()</code>是模板函数</p>
<blockquote>
<p>这里了解一下共享库初始化函数的执行流程</p>
<ol>
<li><p><code>call_function("DT_INIT", init_func_, get_realpath());</code></p>
<p>这行代码调用了 <code>call_function</code> 函数，传递了三个参数：<code>"DT_INIT"</code>、<code>init_func_</code> 和 <code>get_realpath()</code>。其中：</p>
<ul>
<li><code>"DT_INIT"</code> 是一个字符串，用于标识所调用的初始化函数的类型，这里表示调用的是 <code>DT_INIT</code> 函数。</li>
<li><code>init_func_</code> 是一个函数指针，指向了共享库中的 <code>DT_INIT</code> 函数。</li>
<li><code>get_realpath()</code> 是一个函数，用于获取共享库的路径。</li>
</ul>
<p>在函数内部，它会首先检查 <code>init_func_</code> 是否为空，如果不为空，则调用 <code>function()</code> 函数执行初始化操作，即执行共享库中的 <code>DT_INIT</code> 函数。在执行前后，会通过 <code>TRACE</code> 打印调试信息。</p>
</li>
<li><p><code>call_array("DT_INIT_ARRAY", init_array_, init_array_count_, false, get_realpath());</code></p>
<p>这行代码调用了 <code>call_array</code> 函数，传递了五个参数：<code>"DT_INIT_ARRAY"</code>、<code>init_array_</code>、<code>init_array_count_</code>、<code>false</code> 和 <code>get_realpath()</code>。其中：</p>
<ul>
<li><code>"DT_INIT_ARRAY"</code> 是一个字符串，用于标识所调用的初始化数组的类型，这里表示调用的是 <code>DT_INIT_ARRAY</code> 数组。</li>
<li><code>init_array_</code> 是一个指向初始化数组的指针，该数组包含了一系列的初始化函数。</li>
<li><code>init_array_count_</code> 是初始化数组中元素的数量。</li>
<li><code>false</code> 表示不需要对初始化数组进行反向遍历。</li>
<li><code>get_realpath()</code> 是一个函数，用于获取共享库的路径。</li>
</ul>
<p><code>call_array</code> 函数会遍历 <code>init_array_</code> 数组，依次调用数组中的初始化函数。在每次调用初始化函数前后，同样会通过 <code>TRACE</code> 打印调试信息。</p>
<p>这两行代码的作用是在共享库加载过程中，执行共享库中的初始化函数，以完成一些必要的初始化工作，比如初始化全局变量、注册回调函数等。</p>
</li>
</ol>
</blockquote>
</li>
<li><blockquote>
<p>跟进去可以看到*call_function()*函数它的文件路径是在<code>/bionic/linker/linker_soinfo.cpp</code></p>
<pre><code class="C++">/**
 * @brief 调用链接器构造函数
 * 
 * @param function_name 构造函数的名称
 * @param function 构造函数的函数指针
 * @param realpath 文件的实际路径
 */
static void call_function(const char* function_name __unused,
                          linker_ctor_function_t function,
                          const char* realpath __unused) {
    // 如果构造函数为空指针或者指针的值为 -1，则直接返回，不进行任何操作
    if (function == nullptr || reinterpret_cast&lt;uintptr_t&gt;(function) == static_cast&lt;uintptr_t&gt;(-1)) {
        return;
    }

    // 打印调试信息，包括构造函数的名称、函数指针和文件路径
    TRACE("[ Calling c-tor %s @ %p for '%s' ]", function_name, function, realpath);
    
    // 调用构造函数，传递全局变量 g_argc、g_argv 和 g_envp
    function(g_argc, g_argv, g_envp);
    
    // 再次打印调试信息，表示构造函数调用结束
    TRACE("[ Done calling c-tor %s @ %p for '%s' ]", function_name, function, realpath);
}

/**
 * @brief 调用链接器析构函数
 * 
 * @param function_name 析构函数的名称
 * @param function 析构函数的函数指针
 * @param realpath 文件的实际路径
 */
static void call_function(const char* function_name __unused,
                          linker_dtor_function_t function,
                          const char* realpath __unused) {
    // 如果析构函数为空指针或者指针的值为 -1，则直接返回，不进行任何操作
    if (function == nullptr || reinterpret_cast&lt;uintptr_t&gt;(function) == static_cast&lt;uintptr_t&gt;(-1)) {
        return;
    }

    // 打印调试信息，包括析构函数的名称、函数指针和文件路径
    TRACE("[ Calling d-tor %s @ %p for '%s' ]", function_name, function, realpath);
    
    // 调用析构函数
    function();
    
    // 再次打印调试信息，表示析构函数调用结束
    TRACE("[ Done calling d-tor %s @ %p for '%s' ]", function_name, function, realpath);
}
</code></pre>
<ul>
<li>这两个函数的作用分别是调用链接器构造函数（constructor）和析构函数（destructor）。</li>
</ul>
</blockquote>
</li>
</ul>
<h3 id="用Frida获取模块的符号"><a href="#用Frida获取模块的符号" class="headerlink" title="用Frida获取模块的符号"></a>用Frida获取模块的符号</h3><pre><code class="js">function get_addr(){
    var linker_sym = Module.enumerateSymbols("linker")
    console.log("do_dlopen_addr =&gt; ", JSON.stringify(linker_sym))
}
</code></pre>
<ul>
<li><p>linker分为32位和64位两个，32位环境名字是<strong>linker</strong>，64位环境是<strong>linker64</strong></p>
<blockquote>
<p>在脚本打印出的符号中没有看到<code>call_function()</code>，可能是被优化掉了。用IDA确认一下</p>
<ol>
<li><p>用adb命令从手机系统中导出<strong>linker库</strong>文件</p>
<img lazyload="" src="/images/loading.svg" data-src="/2024/04/10/linkHook-init-array%E8%87%AA%E5%90%90/image-20240404213119392.png" class="" title="image-20240404213119392">
</li>
<li><p>在IDA中检查后没有发现<code>call_function()</code></p>
<img lazyload="" src="/images/loading.svg" data-src="/2024/04/10/linkHook-init-array%E8%87%AA%E5%90%90/image-20240404213731538.png" class="" title="image-20240404213731538">

<ul>
<li>可以看到分别调用了构造函数<code>call_constructors()</code>、析构函数<code>call_destructors()</code>、<code>call_array()</code></li>
</ul>
</li>
<li><p>跟进去分析之后发现<code>call_function()</code>函数是被优化成代码片段，插入在<code>call_constructors()</code>、<code>call_array()</code>中间了</p>
<img lazyload="" src="/images/loading.svg" data-src="/2024/04/10/linkHook-init-array%E8%87%AA%E5%90%90/image-20240405221059543.png" class="" title="image-20240405221059543">

<ul>
<li>既然这样的话，根据反编译的伪代码我们可以尝试hook这个<code>_dl_async_safe_format_log()</code>通过这个函数来获取构造函数的名称<code>function_name</code>、函数指针<code>function</code>和文件路径<code>realpath</code></li>
<li>不过需要注意的是，这个函数执行有一个条件是<code>_dl_g_ld_debug_verbosity &gt;= 2</code>，所以在hook这个函数之前先使用frida去这个变量的地址修改它的变量值让<code>_dl_async_safe_format_log()</code>符合执行条件。</li>
</ul>
</li>
</ol>
</blockquote>
</li>
</ul>
<p>通过上面的脚本获取到<strong>linker</strong>的地址之后，根据IDA反编译的结果知道它有5个参数，参照源码参数的类型将结果打印出来，因为函数被优化了所以参数类型跟源码中略有差别，多尝试几次就ok了。</p>
<pre><code class="js">function hook_constructors(linker_sym){
    for(var i = 0; i &lt; linker_sym.length; i++){
        var name = linker_sym[i].name
        if(name.indexOf("__dl_g_ld_debug_verbosity") &gt;= 0){
            var addr__dl_g_ld_debug_verbosity = linker_sym[i].address
            // console.log("addr__dl_g_ld_debug_verbosity =&gt; ", addr__dl_g_ld_debug_verbosity)
            ptr(addr__dl_g_ld_debug_verbosity).writeInt(2)
        }
        if(name.indexOf("__dl_async_safe_format_log") &gt;= 0 &amp;&amp; name.indexOf("va_list") &lt; 0){
            // console.log("__dl_async_safe_format_log", JSON.stringify(linker_sym[i]))
            var addr__dl_async_safe_format_log = linker_sym[i].address
        }
    }
    if(addr__dl_async_safe_format_log){
        Interceptor.attach(addr__dl_async_safe_format_log, {
            onEnter: function(args){
                this.log_level = args[0]
                this.tag = ptr(args[1]).readCString()
                this.fmt = ptr(args[2]).readCString()
                if(this.fmt.indexOf("c-tor") &gt;= 0 &amp;&amp; this.fmt.indexOf("Done") &lt; 0){
                    this.function_type = ptr(args[3]).readCString()
                    this.so_path = ptr(args[5]).readCString()
                    var strs = new Array()	// 创建一个车数组
                    strs = this.so_path.split("/")	// 字符分割
                    this.so_name = strs.pop()
                    this.func_offset = ptr(args[4]).sub(Module.findBaseAddress(this.so_name))
                    console.log("func_type: ", this.function_type,
                    "\nso_name: ", this.so_name,
                    "\nso_path: ", this.so_path,
                    "\nfunc_offset: ", this.func_offset.toString(16))
                }
            }, onLeave: function(retval){}
        })
    }
}
</code></pre>
<img lazyload="" src="/images/loading.svg" data-src="/2024/04/10/linkHook-init-array%E8%87%AA%E5%90%90/image-20240410003035124.png" class="" title="image-20240410003035124">

<img lazyload="" src="/images/loading.svg" data-src="/2024/04/10/linkHook-init-array%E8%87%AA%E5%90%90/image-20240410091216247.png" class="" title="image-20240410091216247">





<h6 id="附件"><a href="#附件" class="headerlink" title="附件"></a>附件</h6><p><a class="link" target="_blank" rel="noopener" href="https://github.com/xiaoeeyu/link_hook/blob/main/init_arrayAuto.js">hook脚本<i class="fa-solid fa-arrow-up-right ml-[0.2em] font-light align-text-top text-[0.7em] link-icon"></i></a></p>

		</div>

		
		<div class="post-copyright-info w-full my-8 px-2 sm:px-6 md:px-8">
			<div class="article-copyright-info-container">
    <ul>
        <li><strong>标题:</strong> linkHook_init_array自吐</li>
        <li><strong>作者:</strong> xiaoeryu</li>
        <li><strong>创建于
                :</strong> 2024-04-10 09:16:22</li>
        
            <li>
                <strong>更新于
                    :</strong> 2024-08-06 22:19:29
            </li>
        
        <li>
            <strong>链接:</strong> https://github.com/xiaoeryu/2024/04/10/linkHook-init-array自吐/
        </li>
        <li>
            <strong>
                版权声明:
            </strong>
            

            
                本文章采用 <a class="license" target="_blank" rel="noopener" href="https://creativecommons.org/licenses/by-nc-sa/4.0">CC BY-NC-SA 4.0</a> 进行许可。
            
        </li>
    </ul>
</div>

		</div>
		

		
		<ul class="post-tags-box text-lg mt-1.5 flex-wrap justify-center flex md:hidden">
			
			<li class="tag-item mx-0.5">
				<a href="/tags/Frida-Hook/">#Frida Hook</a>&nbsp;
			</li>
			
			<li class="tag-item mx-0.5">
				<a href="/tags/%E6%A1%86%E6%9E%B6%E5%B1%82Hook/">#框架层Hook</a>&nbsp;
			</li>
			
		</ul>
		

		

		
		<div class="article-nav my-8 flex justify-between items-center px-2 sm:px-6 md:px-8">
			
			<div class="article-prev border-border-color shadow-redefine-flat shadow-shadow-color-2 rounded-medium px-4 py-2 hover:shadow-redefine-flat-hover hover:shadow-shadow-color-2">
				<a class="prev" rel="prev" href="/2024/05/26/App%E6%8A%93%E5%8C%85%E6%95%99%E7%A8%8B%E6%B1%87%E6%80%BB/">
					<span class="left arrow-icon flex justify-center items-center">
						<i class="fa-solid fa-chevron-left"></i>
					</span>
					<span class="title flex justify-center items-center">
						<span class="post-nav-title-item">App抓包工具教程汇总</span>
						<span class="post-nav-item">上一篇</span>
					</span>
				</a>
			</div>
			
			
			<div class="article-next border-border-color shadow-redefine-flat shadow-shadow-color-2 rounded-medium px-4 py-2 hover:shadow-redefine-flat-hover hover:shadow-shadow-color-2">
				<a class="next" rel="next" href="/2024/03/25/libcHook/">
					<span class="title flex justify-center items-center">
						<span class="post-nav-title-item">libcHook</span>
						<span class="post-nav-item">下一篇</span>
					</span>
					<span class="right arrow-icon flex justify-center items-center">
						<i class="fa-solid fa-chevron-right"></i>
					</span>
				</a>
			</div>
			
		</div>
		


		
		<div class="comment-container px-2 sm:px-6 md:px-8 pb-8">
			<div class="comments-container mt-10 w-full ">
    <div id="comment-anchor" class="w-full h-2.5"></div>
    <div class="comment-area-title w-full my-1.5 md:my-2.5 text-xl md:text-3xl font-bold">
        评论
    </div>
    

        
            


        
    
</div>

		</div>
		
	</div>

	
	<div class="toc-content-container">
		<div class="post-toc-wrap">
	<div class="post-toc">
		<div class="toc-title">目录</div>
		<div class="page-title">linkHook_init_array自吐</div>
		<ol class="nav"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90"><span class="nav-text">源码分析</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%94%A8Frida%E8%8E%B7%E5%8F%96%E6%A8%A1%E5%9D%97%E7%9A%84%E7%AC%A6%E5%8F%B7"><span class="nav-text">用Frida获取模块的符号</span></a></li></ol>

	</div>
</div>
	</div>
	
</div>
			</div>

			
		</div>

		<div class="main-content-footer">
			<footer class="footer mt-5 py-5 h-auto text-base text-third-text-color relative border-t-2 border-t-border-color">
    <div class="info-container py-3 text-center">
        
        <div class="text-center">
            &copy;
            
              <span>2022</span>
              -
            
            2025&nbsp;&nbsp;<i class="fa-solid fa-heart fa-beat" style="--fa-animation-duration: 0.5s; color: #f54545"></i>&nbsp;&nbsp;<a href="/">xiaoeryu</a>
            
                
                <p class="post-count space-x-0.5">
                    <span>
                        共撰写了 112 篇文章
                    </span>
                    
                </p>
            
        </div>
        
            <script data-swup-reload-script src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
            <div class="relative text-center lg:absolute lg:right-[20px] lg:top-1/2 lg:-translate-y-1/2 lg:text-right">
                
                    <span id="busuanzi_container_site_uv" class="lg:!block">
                        <span class="text-sm">访问人数</span>
                        <span id="busuanzi_value_site_uv"></span>
                    </span>
                
                
                    <span id="busuanzi_container_site_pv" class="lg:!block">
                        <span class="text-sm">总访问量</span>
                        <span id="busuanzi_value_site_pv"></span>
                    </span>
                
            </div>
        
        <div class="relative text-center lg:absolute lg:left-[20px] lg:top-1/2 lg:-translate-y-1/2 lg:text-left">
            <span class="lg:block text-sm">由 <?xml version="1.0" encoding="utf-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="relative top-[2px] inline-block align-baseline" version="1.1" id="圖層_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="1rem" height="1rem" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve"><path fill="#0E83CD" d="M256.4,25.8l-200,115.5L56,371.5l199.6,114.7l200-115.5l0.4-230.2L256.4,25.8z M349,354.6l-18.4,10.7l-18.6-11V275H200v79.6l-18.4,10.7l-18.6-11v-197l18.5-10.6l18.5,10.8V237h112v-79.6l18.5-10.6l18.5,10.8V354.6z"/></svg><a target="_blank" class="text-base" href="https://hexo.io">Hexo</a> 驱动</span>
            <span class="text-sm lg:block">主题&nbsp;<a class="text-base" target="_blank" href="https://github.com/EvanNotFound/hexo-theme-redefine">Redefine v2.8.2</a></span>
        </div>
        
        
            <div>
                博客已运行 <span class="odometer" id="runtime_days" ></span> 天 <span class="odometer" id="runtime_hours"></span> 小时 <span class="odometer" id="runtime_minutes"></span> 分钟 <span class="odometer" id="runtime_seconds"></span> 秒
            </div>
        
        
            <script data-swup-reload-script>
                try {
                    function odometer_init() {
                    const elements = document.querySelectorAll('.odometer');
                    elements.forEach(el => {
                        new Odometer({
                            el,
                            format: '( ddd).dd',
                            duration: 200
                        });
                    });
                    }
                    odometer_init();
                } catch (error) {}
            </script>
        
        
        
    </div>  
</footer>
		</div>
	</div>

	
	<div class="post-tools">
		<div class="post-tools-container">
	<ul class="article-tools-list">
		<!-- TOC aside toggle -->
		
		<li class="right-bottom-tools page-aside-toggle">
			<i class="fa-regular fa-outdent"></i>
		</li>
		

		<!-- go comment -->
		
		<li class="go-comment">
			<i class="fa-regular fa-comments"></i>
		</li>
		
	</ul>
</div>
	</div>
	

	<div class="right-side-tools-container">
		<div class="side-tools-container">
	<ul class="hidden-tools-list">
		<li class="right-bottom-tools tool-font-adjust-plus flex justify-center items-center">
			<i class="fa-regular fa-magnifying-glass-plus"></i>
		</li>

		<li class="right-bottom-tools tool-font-adjust-minus flex justify-center items-center">
			<i class="fa-regular fa-magnifying-glass-minus"></i>
		</li>

		<li class="right-bottom-tools tool-dark-light-toggle flex justify-center items-center">
			<i class="fa-regular fa-moon"></i>
		</li>

		<!-- rss -->
		

		

		<li class="right-bottom-tools tool-scroll-to-bottom flex justify-center items-center">
			<i class="fa-regular fa-arrow-down"></i>
		</li>
	</ul>

	<ul class="visible-tools-list">
		<li class="right-bottom-tools toggle-tools-list flex justify-center items-center">
			<i class="fa-regular fa-cog fa-spin"></i>
		</li>
		
		<li class="right-bottom-tools tool-scroll-to-top flex justify-center items-center">
			<i class="arrow-up fas fa-arrow-up"></i>
			<span class="percent"></span>
		</li>
		
		
	</ul>
</div>
	</div>

	<div class="image-viewer-container">
	<img src="">
</div>

	
	<div class="search-pop-overlay">
	<div class="popup search-popup">
		<div class="search-header">
			<span class="search-input-field-pre">
				<i class="fa-solid fa-keyboard"></i>
			</span>
			<div class="search-input-container">
				<input autocomplete="off" autocorrect="off" autocapitalize="off" placeholder="站内搜索您需要的内容..." spellcheck="false" type="search" class="search-input">
			</div>
			<span class="popup-btn-close">
				<i class="fa-solid fa-times"></i>
			</span>
		</div>
		<div id="search-result">
			<div id="no-result">
				<i class="fa-solid fa-spinner fa-spin-pulse fa-5x fa-fw"></i>
			</div>
		</div>
	</div>
</div>
	

</main>



<script src="/js/build/libs/Swup.min.js"></script>

<script src="/js/build/libs/SwupSlideTheme.min.js"></script>

<script src="/js/build/libs/SwupScriptsPlugin.min.js"></script>

<script src="/js/build/libs/SwupProgressPlugin.min.js"></script>

<script src="/js/build/libs/SwupScrollPlugin.min.js"></script>

<script src="/js/build/libs/SwupPreloadPlugin.min.js"></script>

<script>
    const swup = new Swup({
        plugins: [
            new SwupScriptsPlugin({
                optin: true,
            }),
            new SwupProgressPlugin(),
            new SwupScrollPlugin({
                offset: 80,
            }),
            new SwupSlideTheme({
                mainElement: ".main-content-body",
            }),
            new SwupPreloadPlugin(),
        ],
        containers: ["#swup"],
    });
</script>




	
<script src="/js/build/tools/imageViewer.js" type="module"></script>

<script src="/js/build/utils.js" type="module"></script>

<script src="/js/build/main.js" type="module"></script>

<script src="/js/build/layouts/navbarShrink.js" type="module"></script>

<script src="/js/build/tools/scrollTopBottom.js" type="module"></script>

<script src="/js/build/tools/lightDarkSwitch.js" type="module"></script>

<script src="/js/build/layouts/categoryList.js" type="module"></script>



    
<script src="/js/build/tools/localSearch.js" type="module"></script>




    
<script src="/js/build/tools/codeBlock.js" type="module"></script>




    
<script src="/js/build/layouts/lazyload.js" type="module"></script>




    
<script src="/js/build/tools/runtime.js"></script>

    
<script src="/js/build/libs/odometer.min.js"></script>

    
<link rel="stylesheet" href="/assets/odometer-theme-minimal.css">




  
<script src="/js/build/libs/Typed.min.js"></script>

  
<script src="/js/build/plugins/typed.js" type="module"></script>








    
<script src="/js/build/libs/anime.min.js"></script>





    
<script src="/js/build/tools/tocToggle.js" type="module" data-swup-reload-script=""></script>

<script src="/js/build/layouts/toc.js" type="module" data-swup-reload-script=""></script>

<script src="/js/build/plugins/tabs.js" type="module" data-swup-reload-script=""></script>




<script src="/js/build/libs/moment-with-locales.min.js" data-swup-reload-script=""></script>


<script src="/js/build/layouts/essays.js" type="module" data-swup-reload-script=""></script>





	
</body>

</html>